/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of UHM (Unassembled HyperMatrix) sparse direct solver.
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#include "uhm/common.hxx"
#include "uhm/const.hxx"
#include "uhm/util.hxx"

#include "uhm/matrix/uhm/matrix.hxx"

namespace uhm {
  // --------------------------------------------------------------
  // ** Matrix
  double  buffer_used     = 0.0;
  double  max_buffer_used = 0.0;
  double  flop            = 0.0;

  double matrix_buffer_used()     { return buffer_used; }
  double matrix_max_buffer_used() { return max_buffer_used; }
  double matrix_flop()            { return flop; }
  
  void   matrix_reset_flop()      { flop = 0.0; }
  void   matrix_reset_buffer()    { buffer_used = 0.0; max_buffer_used =0.0; }

  // ** Lite util
  void   merge(int datatype,
               double *buf_s, int offm_s, int offn_s, int cs_s,
               double *buf_t, int offm_t, int offn_t, int cs_t,
               int is_erase) {
    switch (datatype) {
    case UHM_SINGLE_REAL:
    case UHM_DOUBLE_REAL:
      {
        buf_t[offn_t*cs_t + offm_t] += buf_s[offn_s*cs_s + offm_s];
        if (is_erase) 
          buf_s[offn_s*cs_s + offm_s] = 0.0;
      }
      break;
    case UHM_SINGLE_COMPLEX:
    case UHM_DOUBLE_COMPLEX:
      {
        buf_t[offn_t*cs_t + offm_t + 0] += buf_s[offn_s*cs_s + offm_s + 0];
        buf_t[offn_t*cs_t + offm_t + 1] += buf_s[offn_s*cs_s + offm_s + 1];
        if (is_erase) {
          buf_s[offn_s*cs_s + offm_s + 0] = 0.0;
          buf_s[offn_s*cs_s + offm_s + 1] = 0.0;
        }
      }
      break;
    }
  }
  void   merge(int datatype,
               double *buf_s, int offm_s, int offn_s, int cs_s,
               double *buf_t, int offm_t, int offn_t, int cs_t,
               int m, int n,
               int is_erase) {
    switch (datatype) {
    case UHM_SINGLE_REAL:
    case UHM_DOUBLE_REAL:
      {
        if (is_erase) {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t] += buf_s[col_s*cs_s + row_s];
              buf_s[col_s*cs_s + row_s]  = 0.0;
            }
        } else {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t] += buf_s[col_s*cs_s + row_s];
            }
        }
      }
      break;
    case UHM_SINGLE_COMPLEX:
    case UHM_DOUBLE_COMPLEX:
      {
        if (is_erase) {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t + 0] += buf_s[col_s*cs_s + row_s + 0];
              buf_t[col_t*cs_t + row_t + 1] += buf_s[col_s*cs_s + row_s + 1];
              buf_s[col_s*cs_s + row_s + 0]  = 0.0;
              buf_s[col_s*cs_s + row_s + 1]  = 0.0;
            }
        } else {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t + 0] += buf_s[col_s*cs_s + row_s + 0];
              buf_t[col_t*cs_t + row_t + 1] += buf_s[col_s*cs_s + row_s + 1];
            }
        }
      }
      break;
    }
  }





  void   copy(int datatype,
              double *buf_s, int offm_s, int offn_s, int cs_s,
              double *buf_t, int offm_t, int offn_t, int cs_t,
              int is_erase) {
    switch (datatype) {
    case UHM_SINGLE_REAL:
    case UHM_DOUBLE_REAL:
      {
        buf_t[offn_t*cs_t + offm_t] = buf_s[offn_s*cs_s + offm_s];
        if (is_erase) 
          buf_s[offn_s*cs_s + offm_s] = 0.0;
      }
      break;
    case UHM_SINGLE_COMPLEX:
    case UHM_DOUBLE_COMPLEX:
      {
        buf_t[offn_t*cs_t + offm_t + 0] = buf_s[offn_s*cs_s + offm_s + 0];
        buf_t[offn_t*cs_t + offm_t + 1] = buf_s[offn_s*cs_s + offm_s + 1];
        if (is_erase) {
          buf_s[offn_s*cs_s + offm_s + 0] = 0.0;
          buf_s[offn_s*cs_s + offm_s + 1] = 0.0;
        }
      }
      break;
    }
  }
  void   copy(int datatype,
              double *buf_s, int offm_s, int offn_s, int cs_s,
              double *buf_t, int offm_t, int offn_t, int cs_t,
              int m, int n,
              int is_erase) {
    switch (datatype) {
    case UHM_SINGLE_REAL:
    case UHM_DOUBLE_REAL:
      {
        if (is_erase) {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t] = buf_s[col_s*cs_s + row_s];
              buf_s[col_s*cs_s + row_s] = 0.0;
            }
        } else {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t] = buf_s[col_s*cs_s + row_s];
            }
        }
      }
      break;
    case UHM_SINGLE_COMPLEX:
    case UHM_DOUBLE_COMPLEX:
      {
        if (is_erase) {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t + 0] = buf_s[col_s*cs_s + row_s + 0];
              buf_t[col_t*cs_t + row_t + 1] = buf_s[col_s*cs_s + row_s + 1];
              buf_s[col_s*cs_s + row_s + 0] = 0.0;
              buf_s[col_s*cs_s + row_s + 1] = 0.0;
            }
        } else {
          for (int j=0;j<n;++j)
            for (int i=0;i<m;++i) {
              int 
                row_t = offm_t + i, col_t = offn_t + j,
                row_s = offm_s + i, col_s = offn_s + j;

              buf_t[col_t*cs_t + row_t + 0] = buf_s[col_s*cs_s + row_s + 0];
              buf_t[col_t*cs_t + row_t + 1] = buf_s[col_s*cs_s + row_s + 1];
            }
        }
      }
      break;
    }
  }

}
